/*
 * CxxUtils.h
 *
 *  Created on: May 5, 2012
 *      Author: wenwei
 */

#ifndef CXXUTILS_H_
#define CXXUTILS_H_

#include <cstring>
#include <cstdio>
#include <exception>
#include <assert.h>
#include <string>
#include <sstream>
#include <vector>
#include <cstdlib>

#ifdef WIN32
#define snprintf _snprintf
#endif

extern long cObjectAllocated;
extern long cObjectFreed;

template <typename T>
class CRefPtr
{
protected:
	class CRefCounter
	{
	protected:
		size_t mCounter;
		CRefCounter(const CRefCounter&);
		CRefCounter& operator=(const CRefCounter&);
	public:
		CRefCounter() : mCounter(0) {};
		~CRefCounter() {};

		size_t Inc() { mCounter++; return mCounter; }
		size_t Dec() { mCounter--; return mCounter; }
	};

	CRefCounter *mRefCounter;
	T *mObjectPtr;

	void Dec() {
		if (mRefCounter && mRefCounter->Dec() == 0) {
			if (mObjectPtr) delete mObjectPtr;
			delete mRefCounter;
			cObjectFreed--;
		}
		mObjectPtr = 0;
		mRefCounter = 0;
	}

	void Dup(const CRefPtr& copy) {
		mRefCounter = copy.mRefCounter;
		if (mRefCounter) mRefCounter->Inc();
		mObjectPtr = copy.mObjectPtr;
	}
public:
	CRefPtr()
		: mRefCounter(0)
		, mObjectPtr(0)
	{
	}

	CRefPtr(T *p)
		: mRefCounter(new CRefCounter())
		, mObjectPtr(p)
	{
		assert(p != NULL);
		mRefCounter->Inc();

		cObjectAllocated++;
	}

	virtual ~CRefPtr()
	{
		Dec();
	}

	CRefPtr(const CRefPtr& copy)
	{
		Dup(copy);
	}

	CRefPtr& operator=(const CRefPtr& copy)
	{
		if (this != &copy) {
			Dec();
			Dup(copy);
		}
		return *this;
	}

	T* get() { return mObjectPtr; }

	const T* get() const { return mObjectPtr; }

	T& operator*() { return *mObjectPtr; }

    T* operator->() { return mObjectPtr; }
	
	const T* operator->() const{ return mObjectPtr; }

    static int _debug_mem_balance() { return cObjectAllocated + cObjectFreed; }

	bool operator==(const CRefPtr& obj) const{ // used by hash map/multimap
		if (!mObjectPtr) return false;
		return mObjectPtr->hashEqual(obj);
	}
};

class CxxException : public std::exception
{
protected:
	char mMsg[256];
	const char *mFile;
	int mLine;

public:
	CxxException(const char *file, int line) throw() {
		mFile = file; mLine = line;
	}
	CxxException(const CxxException& e) throw() {
		*this = e;
	}
	CxxException& operator=(const CxxException& e) throw() {
		mFile = e.mFile; mLine = e.mLine;
		return *this;
	}
	virtual ~CxxException() throw() {}

	virtual const char* what() const throw() {
		snprintf((char *)mMsg, sizeof(mMsg) - 1, "exception at %s:%d\r\n", mFile, mLine);
		return mMsg;
	}
};

#define CXXTHROW throw CxxException(__FILE__, __LINE__);

#endif /* CXXUTILS_H_ */
